﻿using FastORM.Definition;
using FastORM.Entity;
using FastORM.Mapping;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace FastORM.Handle
{
    public class SqlSession
    {
        public IFastDBSQLBuild DBBuild { set; get; }
        public IFastDBExecute DBExecute { set; get; }
        public string ConnectionString { set; get; }
        public void Insert<T>(T Entity) where T : BaseEntity
        {
            DBExecute.ExecuteNoQuery(ConnectionString, DBBuild.BuildInsertSQL(Entity), StructMapping.GetInstance().MapParams(Entity));
        }
        public bool InsertBatch<T>(List<T> EntityList, int BufferSize) where T : BaseEntity
        {
            string ExceptionStr = string.Empty;
            //商
            int groupnum = EntityList.Count / BufferSize;
            //余数
            int grouprest = EntityList.Count - BufferSize * groupnum;
            if (grouprest != 0)
            {
                groupnum++;
            }
            for (int i = 0; i < groupnum; i++)
            {
                ExecuteTransition(delegate ()
                {
                    for (int j = i * BufferSize; j < (i + 1) * BufferSize && j < EntityList.Count; j++)
                    {
                        Insert(EntityList[j]);
                    }
                }, out ExceptionStr);
                if (!string.IsNullOrEmpty(ExceptionStr))
                {
                    break;
                }
            }

            if (string.IsNullOrEmpty(ExceptionStr))
            {
                return true;
            }
            else
            {
                return false;
            }

        }
        public void Insert(string TableName, Hashtable RowData)
        {
            List<ParamEntity> Params = new List<ParamEntity>();
            foreach (string key in RowData.Keys)
            {
                ParamEntity p = new ParamEntity();
                p.ParamName = key;
                p.ParamValue = RowData[key];
                Params.Add(p);
            }
            DBExecute.ExecuteNoQuery(ConnectionString, DBBuild.BuildInsertSQL(TableName, RowData), Params);
        }
        public void Delete<T>(T Entity) where T : BaseEntity
        {
            DBExecute.ExecuteNoQuery(ConnectionString, DBBuild.BuildDeleteSQL(Entity), StructMapping.GetInstance().MapParams(Entity));
        }
        public void Delete<T>(string KeyFieldValue) where T : BaseEntity
        {
            DBExecute.ExecuteNoQuery(ConnectionString, DBBuild.BuildDeleteSQL<T>(), StructMapping.GetInstance().MapKeyParam<T>(KeyFieldValue));
        }
        public void Delete<T>(string FieldName, object FieldValue) where T : BaseEntity
        {
            DBExecute.ExecuteNoQuery(ConnectionString, DBBuild.BuildDeleteSQL<T>(FieldName), new List<ParamEntity>() { new ParamEntity() { ParamName = FieldName, ParamValue = FieldValue } });
        }
        public void Delete(string TableName, string FieldName, object FieldValue)
        {
            DBExecute.ExecuteNoQuery(ConnectionString, DBBuild.BuildDeleteSQL(TableName, FieldName), new List<ParamEntity>() { new ParamEntity() { ParamName = FieldName, ParamValue = FieldValue } });
        }
        public void Update<T>(T Entity) where T : BaseEntity
        {
            DBExecute.ExecuteNoQuery(ConnectionString, DBBuild.BuildUpdateSQL(Entity), StructMapping.GetInstance().MapParams(Entity));
        }
        public void Update<T>(T Entity,string KeyFieldName) where T : BaseEntity
        {
            DBExecute.ExecuteNoQuery(ConnectionString, DBBuild.BuildUpdateSQL(Entity, KeyFieldName), StructMapping.GetInstance().MapParams(Entity));
        }
        public void Update<T>(T Entity, string[] UpdateFileds) where T : BaseEntity
        {
            DBExecute.ExecuteNoQuery(ConnectionString, DBBuild.BuildUpdateSQL(Entity, UpdateFileds), StructMapping.GetInstance().MapParams(Entity));
        }
        public void Update(string TableName, string FieldName, Hashtable RowData)
        {
            List<ParamEntity> Params = new List<ParamEntity>();
            foreach (string key in RowData.Keys)
            {
                ParamEntity p = new ParamEntity();
                p.ParamName = key;
                p.ParamValue = RowData[key];
                Params.Add(p);
            }
            DBExecute.ExecuteNoQuery(ConnectionString, DBBuild.BuildUpdateSQL(TableName, FieldName, RowData), Params);
        }
        public T Find<T>(string KeyFieldValue) where T : BaseEntity
        {
            T Entity = null;
            DataTable dt = DBExecute.ExecuteQuery(ConnectionString, DBBuild.BuildFindSQL<T>(), StructMapping.GetInstance().MapKeyParam<T>(KeyFieldValue));
            if (dt.Rows.Count > 0)
            {
                Entity = StructMapping.GetInstance().MapDataToEntity<T>(dt.Rows[0]);
            }
            return Entity;
        }
        public T Find<T>(string FieldName, object FieldValue) where T : BaseEntity
        {
            T Entity = null;
            DataTable dt = DBExecute.ExecuteQuery(ConnectionString, DBBuild.BuildFindSQL<T>(FieldName), new List<ParamEntity>() { new ParamEntity() { ParamName = FieldName, ParamValue = FieldValue } });
            if (dt.Rows.Count > 0)
            {
                Entity = StructMapping.GetInstance().MapDataToEntity<T>(dt.Rows[0]);
            }
            return Entity;
        }
        public DataTable Find(string TableName, string FieldName, object FieldValue)
        {
            return DBExecute.ExecuteQuery(ConnectionString, DBBuild.BuildFindSQL(TableName, FieldName), new List<ParamEntity>() { new ParamEntity() { ParamName = FieldName, ParamValue = FieldValue } });
        }
        public List<T> FindList<T>(string SQL, List<ParamEntity> Params = null) where T : BaseEntity
        {
            List<T> EntityList = new List<T>();
            DataTable dt = DBExecute.ExecuteQuery(ConnectionString, SQL, Params);
            foreach (DataRow item in dt.Rows)
            {
                EntityList.Add(StructMapping.GetInstance().MapDataToEntity<T>(item));
            }
            return EntityList;
        }
        public List<T> FindList<T>(string Columns, string Where, string OrderBy, List<ParamEntity> Params = null) where T : BaseEntity
        {
            List<T> EntityList = new List<T>();
            DataTable dt = DBExecute.ExecuteQuery(ConnectionString, DBBuild.BuildFindListSQL<T>(Columns, Where, OrderBy), Params);
            foreach (DataRow item in dt.Rows)
            {
                EntityList.Add(StructMapping.GetInstance().MapDataToEntity<T>(item));
            }
            return EntityList;
        }
        public List<T> FindPageList<T>(string Columns, string Where, string OrderBy, int PageIndex, int PageSize, List<ParamEntity> Params = null) where T : BaseEntity
        {
            List<T> EntityList = new List<T>();
            DataTable dt = DBExecute.ExecuteQuery(ConnectionString, DBBuild.BuildFindPageSQL<T>(Columns, Where, OrderBy, PageIndex, PageSize), Params);
            foreach (DataRow item in dt.Rows)
            {
                EntityList.Add(StructMapping.GetInstance().MapDataToEntity<T>(item));
            }
            return EntityList;
        }
        public List<T> FindPageList<T>(string SQL, int PageIndex, int PageSize, List<ParamEntity> Params = null) where T : BaseEntity
        {
            List<T> EntityList = new List<T>();
            DataTable dt = DBExecute.ExecuteQuery(ConnectionString, DBBuild.BuildFindPageSQL<T>(SQL, PageIndex, PageSize), Params);
            foreach (DataRow item in dt.Rows)
            {
                EntityList.Add(StructMapping.GetInstance().MapDataToEntity<T>(item));
            }
            return EntityList;
        }
        public DataTable FindViewList(string SQL, List<ParamEntity> Params = null)
        {
            return DBExecute.ExecuteQuery(ConnectionString, SQL, Params);
        }
        public DataTable FindViewPageList(string SQL, int PageIndex, int PageSize, List<ParamEntity> Params = null)
        {
            return DBExecute.ExecuteQuery(ConnectionString, DBBuild.BuildFindPageSQL(SQL, PageIndex, PageSize), Params);
        }
        public void ExecuteSQL(string SQL, List<ParamEntity> Params = null)
        {
            DBExecute.ExecuteNoQuery(ConnectionString, SQL, Params);
        }
        public object ExecuteScar(string SQL, List<ParamEntity> Params = null)
        {
            return DBExecute.ExecuteScar(ConnectionString, SQL, Params);
        }
        public bool ExecuteTransition(Action TransitionAction, out string ExceptionStr, bool AutoRollBack = true)
        {
            bool IsSuccess = true;
            ExceptionStr = string.Empty;
            string RootThreadID = Thread.CurrentThread.ManagedThreadId.ToString();
            var TrabsitionTask = new Task<LocalTransactionResult>(() =>
            {
                string TransitionID = Thread.CurrentThread.ManagedThreadId.ToString();
                LocalTransactionResult Result = new LocalTransactionResult();
                if (!TransitionManage.ContainsTransition(RootThreadID))
                {
                    DbConnection connection = DBExecute.CreateConnection(ConnectionString);
                    connection.Open();
                    DbTransaction Transaction = connection.BeginTransaction();
                    TransitionManage.AddTransition(TransitionID, RootThreadID, Transaction, TransitionAction);
                    try
                    {
                        TransitionManage.GetTransition(TransitionID).Execute();
                        Transaction.Commit();
                    }
                    catch (System.Exception e)
                    {
                        Result.ExecuteStatus = false;
                        Result.ExceptionMessage = e.Message;
                        if (AutoRollBack)
                        {
                            Transaction.Rollback();
                            Transaction.Dispose();
                            connection.Close();
                            connection.Dispose();
                            Transaction = null;
                            TransitionManage.RemoveTransition(TransitionID);
                        }
                        else
                        {
                            throw e;
                        }
                    }
                    return Result;

                }
                else
                {
                    //当前是嵌套事务，不执行，由根事务统一执行
                    TransitionManage.ContactTransition(TransitionID, RootThreadID, TransitionAction);
                    Result.ExecuteStatus = true;
                    Result.ExceptionMessage = string.Empty;
                    return Result;
                }

            });
            TrabsitionTask.Start();
            TrabsitionTask.Wait();
            IsSuccess = TrabsitionTask.Result.ExecuteStatus;
            ExceptionStr = TrabsitionTask.Result.ExceptionMessage;
            return IsSuccess;

        }
    }
}
